package cn.fornever.tools.db.assist.util;

import cn.fornever.tools.db.assist.entity.ColumnInfo;
import cn.fornever.tools.db.assist.entity.ForeignKeyInfo;
import cn.fornever.tools.db.assist.entity.PrimaryKeyInfo;
import cn.fornever.tools.db.assist.entity.TableInfo;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.JavaTypeResolver;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;

import java.sql.Connection;
import java.sql.JDBCType;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 说明:2017-06-15
 *
 * @author ZhangAY
 *
 */
public interface IDBService {
    List<TableInfo> getTableInfo(Connection connection, String catalog, String schemaPattern, String tableNamePattern, String types[]);

    List<ColumnInfo> getColoumInfo(Connection connection, String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern);

    List<PrimaryKeyInfo> getPrimaryKeyInfo(Connection connection, String catalog, String schemaPattern, String tableNamePattern);

    /**
     * 获取外键信息
     * @param connection 数据库连接
     * @param catalog catalog名称
     * @param schema    schema名称
     * @param tableName table名称
     * @return 外键信息
     */
    List<ForeignKeyInfo> getForeignKeyInfo(Connection connection, String catalog, String schema, String tableName);

    default List<ColumnInfo> setJavaType(List<ColumnInfo> list,Connection connection, String catalog, String schemaPattern, String tableNamePattern){
        if(list != null){
            ColumnInfo columnInfo;
            //1.设置javaTypeName、jdbcTypeName相关
            Integer dataType;
            String javaTypeName;
            String jdbcTypeName;
            JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();
            IntrospectedColumn introspectedColumn= new IntrospectedColumn();
            FullyQualifiedJavaType fullyQualifiedJavaType;
            for(ColumnInfo _columnInfo : list){
                dataType = _columnInfo.getDataType();
                if(dataType != null){
                    jdbcTypeName = JDBCType.valueOf(dataType).getName();
                    _columnInfo.setJdbcTypeName(jdbcTypeName);
                    introspectedColumn.setJdbcType(dataType);
                    fullyQualifiedJavaType = javaTypeResolver.calculateJavaType(introspectedColumn);
                    javaTypeName = fullyQualifiedJavaType.getShortName();
                    _columnInfo.setJavaTypeName(javaTypeName);
                }
            }

            //2.设置 ipPK 属性
            List<PrimaryKeyInfo> primaryKeyInfoList = getPrimaryKeyInfo(connection,catalog,schemaPattern,tableNamePattern);
            Map<String,PrimaryKeyInfo> primaryKeyInfoMap = primaryKeyInfoListtoMap(primaryKeyInfoList);
            Map<String,ColumnInfo> columnInfoMap = columnInfoListtoMap(list);
            //都有相同的key
            PrimaryKeyInfo primaryKeyInfo;
            for (String key : primaryKeyInfoMap.keySet()) {
                if(columnInfoMap.containsKey(key)){
                    primaryKeyInfo = primaryKeyInfoMap.get(key);
                    columnInfo = columnInfoMap.get(key);
                    if(primaryKeyInfo.getColumnName().equals(columnInfo.getColumnName())){
                        columnInfo.setPK(true);
                    }
                }
            }
        }

        return list;
    }

    /**
     * 将 columnInfoList 转换为 Map.
     * 其中Map的key为 TableCat.TableSchem.TableName
     * @param columnInfoList 列信息列表
     * @return 列信息Map
     */
    default Map<String, ColumnInfo> columnInfoListtoMap(List<ColumnInfo> columnInfoList) {
        Map<String, ColumnInfo> resultMap = new LinkedHashMap<>();
        String key;
        for (ColumnInfo columnInfo : columnInfoList) {
            key = buildKey(columnInfo.getTableCat(),columnInfo.getTableSchem(),columnInfo.getTableName());
            resultMap.put(key.toString(),columnInfo);
        }
        return resultMap;
    }

    /**
     * 将 primaryKeyInfoList 转换为 Map.
     * 其中Map的key为 TableCat.TableSchem.TableName
     * @param primaryKeyInfoList 主键信息列表
     * @return 主键信息Map
     */
    default Map<String, PrimaryKeyInfo> primaryKeyInfoListtoMap(List<PrimaryKeyInfo> primaryKeyInfoList) {
        Map<String, PrimaryKeyInfo> resultMap = new LinkedHashMap<>();
        String key;
        for (PrimaryKeyInfo primaryKeyInfo : primaryKeyInfoList) {
            key = buildKey(primaryKeyInfo.getTableCat(),primaryKeyInfo.getTableSchem(),primaryKeyInfo.getTableName());
            resultMap.put(key.toString(),primaryKeyInfo);
        }
        return resultMap;
    }

    /**
     * 将 foreignKeyInfoList 转换为 Map.
     * 其中Map的key为 外键所在表的TableCat.TableSchem.TableName
     * @param foreignKeyInfoList 外键信息列表
     * @return 外键信息Map
     */
    default Map<String, ForeignKeyInfo> foreignKeyInfoListtoMap(List<ForeignKeyInfo> foreignKeyInfoList) {
        Map<String, ForeignKeyInfo> resultMap = new LinkedHashMap<>();
        String key;
        for (ForeignKeyInfo foreignKeyInfo : foreignKeyInfoList) {
            key = buildKey(foreignKeyInfo.getFktableCat(),foreignKeyInfo.getFktableSchem(),foreignKeyInfo.getFktableName());
            resultMap.put(key.toString(),foreignKeyInfo);
        }
        return resultMap;
    }

    /**
     * 构建key
     * @param tableCat tableCat
     * @param tableSchem tableSchem
     * @param tableName tableName
     * @return tableCat.tableSchem.tableName
     */
    default String buildKey(String tableCat,String tableSchem,String tableName){
        StringBuilder key = new StringBuilder();
        key.append(tableCat).append(".");
        key.append(tableSchem).append(".");
        key.append(tableName);
        return key.toString();
    }

    /**
     * 根据 列名称获取对应的列的Index,Index从1开始
     * @param resultSet resultSet
     * @param name name
     * @return 对应的列的Index,如果不包含此列则返回-1
     */
    default Integer getColumnIndexByName(ResultSet resultSet, String name) {
        try {
            return  resultSet.findColumn(name);
        } catch (SQLException e) {
            return -1;
        }
    }

    default Integer string2Integer(String str, Integer defaultValue) {
        if (StringUtils.isNotEmpty(str)) {
            return Integer.valueOf(str);
        }
        return defaultValue;
    }

    default Short string2Short(String str, Short defaultValue) {
        if (StringUtils.isNotEmpty(str)) {
            return Short.valueOf(str);
        }
        return defaultValue;
    }
}
